package org.aphelie.torg.ruler.internal.core.character;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;

import org.aphelie.torg.ruler.core.IEditableModel;
import org.aphelie.torg.ruler.core.IModelChangedEvent;
import org.aphelie.torg.ruler.internal.core.NLResourceHelper;
import org.aphelie.torg.ruler.internal.core.TGRCore;
import org.aphelie.torg.ruler.internal.core.TGRManager;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;


public abstract class WorkspaceCharacterModelBase extends AbstractCharacterModelBase implements IEditableModel {

    private static final long serialVersionUID = 1L;

    private IFile fUnderlyingResource;

    private boolean fDirty;

    private boolean fEditable = true;

    // TODO private IBuildModel fBuildModel;

    protected NLResourceHelper createNLResourceHelper() {
        return new NLResourceHelper("plugin", TGRManager.getNLLookupLocations(this)); //$NON-NLS-1$
    }

    public URL getNLLookupLocation() {
        try {
            return new URL("file:" + getInstallLocation() + "/"); //$NON-NLS-1$ //$NON-NLS-2$
        } catch (MalformedURLException e) {
            return null;
        }
    }

    public WorkspaceCharacterModelBase(IFile file, boolean abbreviated) {
        fUnderlyingResource = file;
        fAbbreviated = abbreviated;
        setEnabled(true);
    }

    public void fireModelChanged(IModelChangedEvent event) {
        fDirty = true;
        super.fireModelChanged(event);
    }

    /* TODO
    public IBuildModel getBuildModel() {
        return fBuildModel;
    }
    */

    public String getContents() {
        StringWriter swriter = new StringWriter();
        PrintWriter writer = new PrintWriter(swriter);
        save(writer);
        writer.flush();
        try {
            swriter.close();
        } catch (IOException e) {
            TGRCore.logException(e);
        }
        return swriter.toString();
    }

    public IFile getFile() {
        return fUnderlyingResource;
    }

    public String getInstallLocation() {
        IPath path = fUnderlyingResource.getLocation();
        return path == null ? null : path.removeLastSegments(1).addTrailingSeparator().toOSString();
    }

    public IResource getUnderlyingResource() {
        return fUnderlyingResource;
    }

    public boolean isInSync() {
        if (fUnderlyingResource == null)
            return true;
        IPath path = fUnderlyingResource.getLocation();
        if (path == null)
            return false;
        return super.isInSync(path.toFile());
    }

    public boolean isDirty() {
        return fDirty;
    }

    public boolean isEditable() {
        return fEditable;
    }

    public void load() {
        if (fUnderlyingResource == null)
            return;
        if (fUnderlyingResource.exists()) {
            InputStream stream = null;
            try {
                stream = new BufferedInputStream(fUnderlyingResource.getContents(true));
                load(stream, false);
            } catch (CoreException e) {
                TGRCore.logException(e);
            } finally {
                try {
                    if (stream != null)
                        stream.close();
                } catch (IOException e) {
                    TGRCore.logException(e);
                }
            }
        } else {
            fCharacterBase = createCharacterBase();
            setLoaded(true);
        }
    }

    protected void updateTimeStamp() {
        updateTimeStamp(fUnderlyingResource.getLocation().toFile());
    }

    public void save() {
        if (fUnderlyingResource == null)
            return;
        ByteArrayInputStream stream = null;
        try {
            String contents = getContents();
            stream = new ByteArrayInputStream(contents.getBytes("UTF8")); //$NON-NLS-1$
            if (fUnderlyingResource.exists()) {
                fUnderlyingResource.setContents(stream, false, false, null);
            } else {
                fUnderlyingResource.create(stream, false, null);
            }
            stream.close();
        } catch (CoreException e) {
            TGRCore.logException(e);
        } catch (IOException e) {
            TGRCore.logException(e);
        } finally {
            try {
                if (stream != null)
                    stream.close();
            } catch (IOException e) {
                TGRCore.logException(e);
            }
        }
    }

    public void save(PrintWriter writer) {
        if (isLoaded()) {
            fCharacterBase.write("", writer); //$NON-NLS-1$
        }
        fDirty = false;
    }

    /*
    public void setBuildModel(IBuildModel buildModel) {
        fBuildModel = buildModel;
    }
    */

    public void setDirty(boolean dirty) {
        fDirty = dirty;
    }

    public void setEditable(boolean editable) {
        fEditable = editable;
    }

}
